home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 001 / fue / c / LINE < prev    next >
Text File  |  1991-04-03  |  44KB  |  1,227 lines

  1. /*
  2.  * The functions in this file are a general set of line management utilities.
  3.  * They are the only routines that touch the text. They also touch the buffer
  4.  * and window structures, to make sure that the necessary updating gets done.
  5.  * There are routines in this file that handle the kill buffer too. It isn't
  6.  * here for any good reason.
  7.  *
  8.  * Note that this code only updates the dot and mark values in the window list.
  9.  * Since all the code acts on the current window, the buffer that we are
  10.  * editing must be being displayed, which means that "b_nwnd" is non zero,
  11.  * which means that the dot and mark values in the buffer headers are nonsense.
  12.  */
  13.  
  14. /*      Modifications:
  15.         11-Sep-89       Mike Burrow (INMOS)     Added folding.
  16. */
  17.  
  18. #include        <stdio.h>
  19. #include        "estruct.h"
  20. #include        "etype.h"
  21. #include        "edef.h"
  22. #include        "elang.h"
  23.  
  24. #define BSIZE(a)        (a + NBLOCK - 1) & (~(NBLOCK - 1))
  25.  
  26. /* variables to count recursion */
  27. int intoindentfold = 0;
  28. int intoundentfold = 0;
  29.  
  30.  
  31. /* Do something, but not much! if we detect an error.
  32.  * MJB: 20-Sep-89.
  33.  */
  34. PASCAL NEAR beep()
  35. {
  36.         TTputc(BELL);
  37.         return(FALSE);
  38. }
  39.  
  40.  
  41. /*
  42.  * Insert spaces so no line is shorter than the left margin value.
  43.  */
  44. PASCAL NEAR marginchk(lp, oset)
  45. LINE *lp;
  46. int  oset;
  47. {
  48.         LINE    *olddotp;
  49.         int     olddoto, i;
  50.  
  51.         /*if ((oset = loffset(lp)) < lp->l_lmargin) {*/
  52.         if (oset < lp->l_lmargin) {
  53.  
  54.                 /* save old values and setup for insert */
  55.                 if (lp != curwp->w_dotp){
  56.                         olddotp = curwp->w_dotp;
  57.                         curwp->w_dotp = lp;
  58.                 }
  59.                 else
  60.                         olddotp = (LINE *) NULL;
  61.  
  62.                 olddoto = curwp->w_doto;
  63.                 curwp->w_doto = oset;
  64.  
  65.                 for (i = oset; i < lp->l_lmargin; i++)
  66.                         linsert(1, lp->l_bp->l_text[i], FALSE);
  67.  
  68.                 /* reset values */
  69.                 if (olddotp != (LINE *)NULL)
  70.                         curwp->w_dotp = olddotp;
  71.                 if (olddoto < curwp->w_dotp->l_lmargin)
  72.                         curwp->w_doto = curwp->w_dotp->l_lmargin;
  73.                 else
  74.                         curwp->w_doto = olddoto;
  75.         }
  76.         return(TRUE);
  77. }
  78.  
  79.  
  80. /*
  81.  * This routine allocates a block of memory large enough to hold a LINE
  82.  * containing "used" characters. Return a pointer to the new block, or
  83.  * NULL if there isn't any memory left. Print a message in the message
  84.  * line if no space.
  85.  */
  86.  
  87. LINE *PASCAL NEAR lalloc(used)
  88.  
  89. register int used;
  90.  
  91. {
  92.         register LINE   *lp;
  93.  
  94.         if ((lp = (LINE *)malloc(sizeof(LINE)+used)) == NULL) {
  95.                 mlwrite(TEXT99);
  96. /*                      "[OUT OF MEMORY]" */
  97.                 return(NULL);
  98.         }
  99.         lp->l_size = used;
  100.         lp->l_used = used;
  101.         lp->l_lmargin = 0;
  102.         lp->l_omargin = 0;
  103.         lp->l_type = LNORMAL;
  104.         lp->l_foldp = (LINE *)NULL;
  105.         return(lp);
  106. }
  107.  
  108. /*
  109.  * Delete line "lp". Fix all of the links that might point at it (they are
  110.  * moved to offset 0 of the next line. Unlink the line from whatever buffer it
  111.  * might be in. Release the memory. The buffers are updated too; the magic
  112.  * conditions described in the above comments don't hold here.
  113.  */
  114. PASCAL NEAR lfree(lp)
  115. register LINE   *lp;
  116. {
  117.         register BUFFER *bp;
  118.         register WINDOW *wp;
  119.         register int cmark;             /* current mark */
  120.  
  121.         wp = wheadp;
  122.         while (wp != NULL) {
  123.                 if (wp->w_linep == lp)
  124.                         wp->w_linep = lp->l_fp;
  125.                 if (wp->w_dotp  == lp) {
  126.                         wp->w_dotp  = lp->l_fp;
  127.                         wp->w_doto  = 0;
  128.                 }
  129.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  130.                         if (wp->w_markp[cmark] == lp) {
  131.                                 wp->w_markp[cmark] = lp->l_fp;
  132.                                 wp->w_marko[cmark] = 0;
  133.                         }
  134.                 }
  135.                 wp = wp->w_wndp;
  136.         }
  137.         bp = bheadp;
  138.         while (bp != NULL) {
  139.                 if (bp->b_nwnd == 0) {
  140.                         if (bp->b_dotp  == lp) {
  141.                                 bp->b_dotp = lp->l_fp;
  142.                                 bp->b_doto = 0;
  143.                         }
  144.                         for (cmark = 0; cmark < NMARKS; cmark++) {
  145.                                 if (bp->b_markp[cmark] == lp) {
  146.                                         bp->b_markp[cmark] = lp->l_fp;
  147.                                         bp->b_marko[cmark] = 0;
  148.                                 }
  149.                         }
  150.                 }
  151.                 bp = bp->b_bufp;
  152.         }
  153.         lp->l_bp->l_fp = lp->l_fp;
  154.         lp->l_fp->l_bp = lp->l_bp;
  155.         free((char *) lp);
  156. }
  157.  
  158. /* Given a line, return the index of the first non whitespace
  159.  * character. MJB: 25-Sep-89. 
  160.  */
  161. int PASCAL NEAR loffset(lp)
  162. LINE * lp;
  163. {
  164.         int i;
  165.  
  166.         i = 0;
  167.         while ((i < lp->l_used) &&
  168.                ((lp->l_text[i] == ' ') ||
  169.                 (lp->l_text[i] == '\t')))
  170.                 i++;
  171.         return(i);
  172. }
  173.  
  174.  
  175. /* Given a line pointer, find the next one to use.
  176.  * This is only called by lforw. MJB: 14-Sep-89.
  177.  * Changed for open fold symbols. MJB 28-Sep-89.
  178.  */
  179. LINE *PASCAL NEAR nxtfwd(lp)
  180. register LINE   *lp;
  181. {
  182.         if ((lp->l_type == LEOFOLD))
  183.                 return(nxtfwd(lp->l_fp));
  184.         else
  185.                 return(lp);
  186. }
  187.  
  188.  
  189. /* Get the next line, this replaces the previous macro,
  190.  * required with the introduction of folding and line
  191.  * types. MJB: 14-Sep-89.
  192.  */
  193. LINE *PASCAL NEAR lforw(lp)
  194. register LINE   *lp;
  195. {
  196.         if (lp->l_type == LSOFOLD)
  197.                 return(nxtfwd(lp->l_foldp));
  198.         else 
  199.                 return(nxtfwd(lp->l_fp));
  200. }
  201.  
  202.  
  203. /* Given a line pointer, find the previous one to use.
  204.  * This is only called by lback. MJB: 14-Sep-89.
  205.  */
  206. LINE *PASCAL NEAR nxtbwd(lp)
  207. register LINE   *lp;
  208. {
  209.         if (lp->l_type == LEOFOLD)
  210.                 return(nxtbwd(lp->l_foldp));
  211.         else 
  212.                 return(lp);
  213. }
  214.  
  215.  
  216. /* Get the previous line, this replaces the previous macro,
  217.  * required with the introduction of folding and line
  218.  * types. MJB: 14-Sep-89.
  219.  */
  220. LINE *PASCAL NEAR lback(lp)
  221. register LINE   *lp;
  222. {
  223.         if (lp->l_type == LEOFOLD)
  224.                 return(nxtbwd(lp->l_foldp));
  225.         else
  226.                 return(nxtbwd(lp->l_bp));
  227. }
  228.  
  229.  
  230. /*
  231.  * This routine gets called when a character is changed in place in the current
  232.  * buffer. It updates all of the required flags in the buffer and window
  233.  * system. The flag used is passed as an argument; if the buffer is being
  234.  * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
  235.  * mode line needs to be updated (the "*" has to be set).
  236.  */
  237. PASCAL NEAR lchange(flag)
  238. register int    flag;
  239. {
  240.         register WINDOW *wp;
  241.  
  242.         if (curbp->b_nwnd != 1)                 /* Ensure hard.         */
  243.                 flag = WFHARD;
  244.         if ((curbp->b_flag&BFCHG) == 0) {       /* First change, so     */
  245.                 flag |= WFMODE;                 /* update mode lines.   */
  246.                 curbp->b_flag |= BFCHG;
  247.         }
  248.  
  249.         /* make sure all the needed windows get this flag */
  250.         wp = wheadp;
  251.         while (wp != NULL) {
  252.                 if (wp->w_bufp == curbp)
  253.                         wp->w_flag |= flag;
  254.                 wp = wp->w_wndp;
  255.         }
  256. }
  257.  
  258. PASCAL NEAR insspace(f, n)      /* insert spaces forward into text */
  259.  
  260. int f, n;       /* default flag and numeric argument */
  261.  
  262. {
  263.         linsert(n, ' ', TRUE);
  264.         backchar(f, n);
  265. }
  266.  
  267. /*
  268.  * linstr -- Insert a string at the current point
  269.  */
  270.  
  271. PASCAL NEAR linstr(instr)
  272. char    *instr;
  273. {
  274.         register int status = TRUE;
  275.  
  276.         if (instr != NULL)
  277.                 while (*instr && status == TRUE) {
  278.                         status = ((*instr == '\r') ? lnewline (): 
  279.                                                      linsert(1, *instr, TRUE));
  280.  
  281.                         /* Insertion error? */
  282.                         if (status != TRUE) {
  283.                                 mlwrite(TEXT168);
  284. /*                                      "%%Can not insert string" */
  285.                                 break;
  286.                         }
  287.                         instr++;
  288.                 }
  289.         return(status);
  290. }
  291.  
  292.  
  293. /*
  294.  * indent the contents of a fold
  295.  */
  296. PASCAL NEAR indentfold(n, c, margmode)
  297. int     n;
  298. char    c;
  299. int     margmode;
  300. {
  301.         LINE    *olddotp;
  302.         int     olddoto;
  303.  
  304.         intoindentfold++;
  305.         olddotp = curwp->w_dotp; 
  306.         olddoto = curwp->w_doto;
  307.         curwp->w_dotp = curwp->w_dotp->l_fp; /* jump round fold */
  308.         while (curwp->w_dotp != olddotp->l_foldp->l_fp) {
  309.                 /* set offset & let recursion take over  */
  310.                 curwp->w_doto = olddoto;
  311.                 if (curwp->w_dotp->l_type == LEOFOLD){
  312.                         curwp->w_dotp->l_type = LNORMAL;
  313.                         linsert(n, c, FALSE); /* bodge to allow prefix */
  314.                         curwp->w_dotp->l_type = LEOFOLD;
  315.                 }
  316.                 else if (curwp->w_dotp->l_type == LEOEFOLD){
  317.                         curwp->w_dotp->l_type = LNORMAL;
  318.                         linsert(n, c, FALSE); /* bodge to allow prefix */
  319.                         curwp->w_dotp->l_type = LEOEFOLD;
  320.                 }
  321.                 else
  322.                         linsert(n, c, FALSE);
  323.  
  324.                 /* move left margin */
  325.                 curwp->w_dotp->l_lmargin += n;
  326.  
  327.                 lchange(WFHARD);
  328.                 /* get next line - end of folds are valid */
  329.                 if ((curwp->w_dotp->l_type == LSOFOLD) ||
  330.                     (curwp->w_dotp->l_type == LSOEFOLD))
  331.                         curwp->w_dotp = curwp->w_dotp->l_foldp;
  332.                 curwp->w_dotp = curwp->w_dotp->l_fp;
  333.         }
  334.         curwp->w_dotp = olddotp;
  335.         curwp->w_doto = olddoto;
  336.  
  337.         if (!--intoindentfold)
  338.                 /* we have moved the left margin of close-fold, so move it back */
  339.                 curwp->w_dotp->l_foldp->l_lmargin -= n;
  340. }
  341.  
  342.  
  343. /*
  344.  * Insert "n" copies of the character "c" at the current location of dot. In
  345.  * the easy case all that happens is the text is stored in the line. In the
  346.  * hard case, the line has to be reallocated. When the window list is updated,
  347.  * take special care; I screwed it up once. You always update dot in the
  348.  * current window. You update mark, and a dot in another window, if it is
  349.  * greater than the place where you did the insert. Return TRUE if all is
  350.  * well, and FALSE on errors.
  351.  */
  352.  
  353. PASCAL NEAR linsert(n, c, margmode)
  354. int     n;
  355. char    c;
  356. int     margmode; /* if true use left margin, else ignore */
  357. {
  358.         register char   *cp1;
  359.         register char   *cp2;
  360.         register LINE   *lp1;
  361.         register LINE   *lp2;
  362.         register LINE   *lp3;
  363.         register int    doto;
  364.         register int    i;
  365.         register WINDOW *wp;
  366.         int cmark;              /* current mark */
  367.  
  368.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  369.                 return(rdonly());       /* we are in read only mode     */
  370.  
  371.         /* check if before left margin of an open fold */
  372.         if ((curwp->w_dotp->l_type == LNORMAL) && margmode &&
  373.             (curwp->w_doto < curwp->w_dotp->l_lmargin))
  374.                 return(beep());
  375.  
  376.         /* check if attempting to edit a fold symbol. MJB: 20-Sep-89 */
  377.         if ((curwp->w_dotp->l_type == LEOFOLD) ||
  378.             (curwp->w_dotp->l_type == LEOEFOLD)) 
  379.                 return(beep());
  380.         if ((curwp->w_dotp->l_type == LSOFOLD) ||
  381.             (curwp->w_dotp->l_type == LSOEFOLD)) {
  382.                 if (curwp->w_dotp->l_type == LSOFOLD)
  383.                         i = indx(curwp->w_dotp->l_text, FOLDSYMBOL);
  384.                 else
  385.                         i = indx(curwp->w_dotp->l_text, BEGINFOLD);
  386.                 if ((curwp->w_doto > i) && 
  387.                     (curwp->w_doto < i + strlen(FOLDSYMBOL)))
  388.                         return(beep()); /* in fold symbol */
  389.                 else if ((curwp->w_doto <= i) && (c != ' ') && (c != '\t'))
  390.                         return(beep()); /* non space before fold */
  391.                 else if ((curwp->w_doto < i) && (c == '\t') &&
  392.                          margmode)
  393.                                 return(beep()); /* tab over margin boundary? */
  394.                 else if ((curwp->w_doto <= i) && (c == ' ') || (c == '\t')) 
  395.                                 indentfold(n, c, margmode);
  396.         }
  397.  
  398.         lchange(WFEDIT);
  399.         lp1 = curwp->w_dotp;                    /* Current line         */
  400.         if (lp1 == curbp->b_linep) {            /* At the end: special  */
  401.                 if (curwp->w_doto != 0) {
  402.                         mlwrite(TEXT170);
  403. /*                              "bug: linsert" */
  404.                         return(FALSE);
  405.                 }
  406.                 if ((lp2=lalloc(BSIZE(n))) == NULL)     /* Allocate new line    */
  407.                         return(FALSE);
  408.                 lp2->l_used = n;
  409.                 lp2->l_type = LNORMAL;          /* MJB: 11-Sep-89       */
  410.                 lp2->l_foldp = (LINE *)NULL;    /* MJB: 11-Sep-89       */
  411.                 lp2->l_lmargin = lp1->l_lmargin;
  412.                 lp2->l_omargin = lp1->l_omargin;
  413.                 lp3 = lp1->l_bp;                /* Previous line        */
  414.                 lp3->l_fp = lp2;                /* Link in              */
  415.                 lp2->l_fp = lp1;
  416.                 lp1->l_bp = lp2;
  417.                 lp2->l_bp = lp3;
  418.                 for (i=0; i<n; ++i)
  419.                         lp2->l_text[i] = c;
  420.                 curwp->w_dotp = lp2;
  421.                 curwp->w_doto = n;
  422.                 return(TRUE);
  423.         }
  424.         doto = curwp->w_doto;                   /* Save for later.      */
  425.         if (lp1->l_used+n > lp1->l_size) {      /* Hard: reallocate     */
  426.                 if ((lp2=lalloc(BSIZE(lp1->l_used+n))) == NULL)
  427.                         return(FALSE);
  428.                 lp2->l_used = lp1->l_used+n;
  429.                 lp2->l_type = lp1->l_type;      /* MJB: 11-Sep-89       */
  430.                 lp2->l_foldp = lp1->l_foldp;    /* MJB: 11-Sep-89       */
  431.                 lp2->l_lmargin = lp1->l_lmargin;  /* MJB: 16-Oct-89     */
  432.                 lp2->l_omargin = lp1->l_omargin;
  433.                 if (lp2->l_foldp != (LINE *)NULL) /* MJB: 27-Sep-89     */
  434.                         lp2->l_foldp->l_foldp = lp2;
  435.                 cp1 = &lp1->l_text[0];
  436.                 cp2 = &lp2->l_text[0];
  437.                 while (cp1 != &lp1->l_text[doto])
  438.                         *cp2++ = *cp1++;
  439.                 cp2 += n;
  440.                 while (cp1 != &lp1->l_text[lp1->l_used])
  441.                         *cp2++ = *cp1++;
  442.                 lp1->l_bp->l_fp = lp2;
  443.                 lp2->l_fp = lp1->l_fp;
  444.                 lp1->l_fp->l_bp = lp2;
  445.                 lp2->l_bp = lp1->l_bp;
  446.                 free((char *) lp1);
  447.         } else {                                /* Easy: in place       */
  448.                 lp2 = lp1;                      /* Pretend new line     */
  449.                 lp2->l_used += n;
  450.                 cp2 = &lp1->l_text[lp1->l_used];
  451.                 cp1 = cp2-n;
  452.                 while (cp1 != &lp1->l_text[doto])
  453.                         *--cp2 = *--cp1;
  454.         }
  455.         for (i=0; i<n; ++i)                     /* Add the characters   */
  456.                 lp2->l_text[doto+i] = c;
  457.         wp = wheadp;                            /* Update windows       */
  458.         while (wp != NULL) {
  459.                 if (wp->w_linep == lp1)
  460.                         wp->w_linep = lp2;
  461.                 if (wp->w_dotp == lp1) {
  462.                         wp->w_dotp = lp2;
  463.                         if (wp==curwp || wp->w_doto>doto)
  464.                                 wp->w_doto += n;
  465.                 }
  466.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  467.                         if (wp->w_markp[cmark] == lp1) {
  468.                                 wp->w_markp[cmark] = lp2;
  469.                                 if (wp->w_marko[cmark] > doto)
  470.                                         wp->w_marko[cmark] += n;
  471.                         }
  472.                 }
  473.                 wp = wp->w_wndp;
  474.         }
  475.         return(TRUE);
  476. }
  477.  
  478. /*
  479.  * Overwrite a character into the current line at the current position
  480.  *
  481.  */
  482.  
  483. PASCAL NEAR lowrite(c)
  484.  
  485. char c;         /* character to overwrite on current position */
  486.  
  487. {
  488.         if (curwp->w_doto < curwp->w_dotp->l_used &&
  489.                 (lgetc(curwp->w_dotp, curwp->w_doto) != '\t' ||
  490.                  (curwp->w_doto) % 8 == 7))
  491.                         ldelete (1L, FALSE, FALSE, TRUE);
  492.         return(linsert(1, c, TRUE));
  493. }
  494.  
  495. /*
  496.  * lover -- Overwrite a string at the current point
  497.  */
  498.  
  499. PASCAL NEAR lover(ostr)
  500.  
  501. char    *ostr;
  502.  
  503. {
  504.         register int status = TRUE;
  505.  
  506.         if (ostr != NULL)
  507.                 while (*ostr && status == TRUE) {
  508.                         status = ((*ostr == '\r') ? lnewline(): lowrite(*ostr));
  509.  
  510.                         /* Insertion error? */
  511.                         if (status != TRUE) {
  512.                                 mlwrite(TEXT172);
  513. /*                                      "%%Out of memory while overwriting" */
  514.                                 break;
  515.                         }
  516.                         ostr++;
  517.                 }
  518.         return(status);
  519. }
  520.  
  521. /*
  522.  * Insert a newline into the buffer at the current location of dot in the
  523.  * current window. The funny ass-backwards way it does things is not a botch;
  524.  * it just makes the last line in the file not a special case. Return TRUE if
  525.  * everything works out and FALSE on error (memory allocation failure). The
  526.  * update of dot and mark is a bit easier then in the above case, because the
  527.  * split forces more updating.
  528.  */
  529. PASCAL NEAR lnewline()
  530. {
  531.         register char   *cp1;
  532.         register char   *cp2;
  533.         register LINE   *lp1;
  534.         register LINE   *lp2;
  535.         register LINE   *lpx;
  536.         register int    doto;
  537.         register WINDOW *wp;
  538.         int cmark;              /* current mark */
  539.         int oset;
  540.         int backup;
  541.  
  542.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  543.                 return(rdonly());       /* we are in read only mode     */
  544.  
  545.         if (curwp->w_doto < curwp->w_dotp->l_lmargin)
  546.                 return(beep());
  547.  
  548.         backup = FALSE;
  549.  
  550.         if (curwp->w_dotp->l_type != LNORMAL) {
  551.                 if ((curwp->w_doto != loffset(curwp->w_dotp)) && 
  552.                     (curwp->w_doto != curwp->w_dotp->l_used))
  553.                         return(beep()); /* Only ends of fold lines. MJB: 20-Sep-89 */
  554.                 else if (curwp->w_doto == curwp->w_dotp->l_used) {
  555.                         /* if at end of fold line, we really mean after the
  556.                            fold!, so goto the beginning of the line after the
  557.                            fold. MJB 22-Sep-89 */
  558.                         curwp->w_dotp = lforw(curwp->w_dotp);
  559.                         if (curwp->w_dotp->l_type == LEOEFOLD)  /* empty fold */
  560.                                 curwp->w_doto = loffset(curwp->w_dotp);
  561.                         else
  562.                                 curwp->w_doto = curwp->w_dotp->l_lmargin;
  563.                         backup = TRUE; /* have to backup in the end */
  564.                 }
  565.                 else if ((curwp->w_dotp->l_type == LSOFOLD) ||
  566.                          (curwp->w_dotp->l_type == LSOEFOLD)) {
  567.                         /* must be at start of fold symbol and need to */ 
  568.                         /* remove any prefix from WHOLE fold */
  569.                         oset = curwp->w_doto - curwp->w_dotp->l_lmargin;
  570.                         if (oset) {
  571.                                 curwp->w_doto = curwp->w_dotp->l_lmargin;
  572.                                 ldelete((long)oset, FALSE, FALSE, FALSE);
  573.                         }
  574.                 }
  575.  
  576.         }
  577.  
  578.         lchange(WFHARD);
  579.         lp1  = curwp->w_dotp;                   /* Get the address and  */
  580.         doto = curwp->w_doto;                   /* offset of "."        */
  581.         if ((lp2=lalloc(doto)) == NULL)         /* New first half line  */
  582.                 return(FALSE);
  583.         lp2->l_type = LNORMAL;  
  584.         lp2->l_foldp = (LINE *)NULL;
  585.         if (lp1->l_type == LEOEFOLD) {
  586.                 lpx = lback(lp1); /* pointer to required indentation */
  587.                 if (lpx->l_type == LSOEFOLD) /* fold open & empty */
  588.                         lp2->l_lmargin = loffset(lpx);
  589.                 else
  590.                         lp2->l_lmargin = lpx->l_lmargin;
  591.                 lp2->l_omargin = lpx->l_omargin;
  592.         }
  593.         else {
  594.                 lp2->l_lmargin = lp1->l_lmargin;
  595.                 lp2->l_omargin = lp1->l_omargin;
  596.         }
  597.         
  598.         cp1 = &lp1->l_text[0];                  /* Shuffle text around  */
  599.         cp2 = &lp2->l_text[0];
  600.         while (cp1 != &lp1->l_text[doto])
  601.                 *cp2++ = *cp1++;
  602.  
  603.         if (lp1->l_type != LEOEFOLD) {
  604.                 cp2 = &lp1->l_text[lp1->l_lmargin];
  605.                 while (cp1 != &lp1->l_text[lp1->l_used])
  606.                         *cp2++ = *cp1++;
  607.  
  608.                 lp1->l_used = lp1->l_used - doto + lp1->l_lmargin;
  609.         }
  610.  
  611.         lp2->l_bp = lp1->l_bp;
  612.         lp1->l_bp = lp2;
  613.         lp2->l_bp->l_fp = lp2;
  614.         lp2->l_fp = lp1;
  615.  
  616.         wp = wheadp;                            /* Windows              */
  617.         while (wp != NULL) {
  618.                 if (wp->w_linep == lp1)
  619.                         wp->w_linep = lp2;
  620.                 if (wp->w_dotp == lp1) {
  621.                         if ((wp->w_doto < doto) || backup){
  622.                                 wp->w_dotp = lp2;
  623.                                 wp->w_doto = lp2->l_lmargin;
  624.                         }
  625.                         else if (lp1->l_type != LEOEFOLD)
  626.                                 wp->w_doto -= (doto - lp1->l_lmargin);
  627.                 }
  628.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  629.                         if (wp->w_markp[cmark] == lp1) {
  630.                                 if (wp->w_marko[cmark] < doto)
  631.                                         wp->w_markp[cmark] = lp2;
  632.                                 else
  633.                                         wp->w_marko[cmark] -= doto;
  634.                         }
  635.                 }
  636.                 wp = wp->w_wndp;
  637.         }
  638.         return(TRUE);
  639. }
  640.  
  641.  
  642. /*
  643.  * Undent the contents of a fold
  644.  */
  645. PASCAL NEAR undentfold(n, i, kflag, rawmode, margmode)
  646. long    n;
  647. int     i;
  648. int     kflag;
  649. int     rawmode;
  650. int     margmode;
  651. {
  652.         LINE    *olddotp;
  653.         int     olddoto;
  654.  
  655.         intoundentfold++;
  656.         olddotp = curwp->w_dotp; 
  657.         olddoto = curwp->w_doto;
  658.         curwp->w_dotp = curwp->w_dotp->l_fp; /* jump round fold */
  659.         while (curwp->w_dotp != olddotp->l_foldp->l_fp) {
  660.  
  661.                 /* move left margin */
  662.                 curwp->w_dotp->l_lmargin -= n;
  663.  
  664.                 /* set offset & let recursion take over  */
  665.                 curwp->w_doto = olddoto;
  666.                 if (curwp->w_dotp->l_type == LEOFOLD) {
  667.                         curwp->w_dotp->l_type = LNORMAL;
  668.                         if ((i = loffset(curwp->w_dotp)) > n)
  669.                                 i = n;
  670.                         ldelete((long)i, kflag, rawmode, FALSE);
  671.                         curwp->w_dotp->l_type = LEOFOLD;
  672.                 }
  673.                 else if (curwp->w_dotp->l_type == LEOEFOLD) {
  674.                         curwp->w_dotp->l_type = LNORMAL;
  675.                         if ((i = loffset(curwp->w_dotp)) > n)
  676.                                 i = n;
  677.                         ldelete((long)i, kflag, rawmode, FALSE);
  678.                         curwp->w_dotp->l_type = LEOEFOLD;
  679.                 }
  680.                 else {
  681.                         if ((i = loffset(curwp->w_dotp)) > n)
  682.                                 i = n;
  683.                         ldelete((long)i, kflag, rawmode, FALSE);
  684.                 }
  685.  
  686.                 lchange(WFHARD);
  687.                 /* get next line - end of folds are valid */
  688.                 if ((curwp->w_dotp->l_type == LSOFOLD) ||
  689.                     (curwp->w_dotp->l_type == LSOEFOLD))
  690.                         curwp->w_dotp = curwp->w_dotp->l_foldp;
  691.                 curwp->w_dotp = curwp->w_dotp->l_fp;
  692.         }
  693.         curwp->w_dotp = olddotp;
  694.         curwp->w_doto = olddoto;
  695.  
  696.         if (!--intoundentfold)
  697.                 /* we have moved the left margin of close-fold, so move it back */
  698.                 curwp->w_dotp->l_foldp->l_lmargin += n;
  699. }
  700.  
  701.  
  702. /*
  703.  * This function deletes "n" bytes, starting at dot. It understands how to deal
  704.  * with end of lines, etc. It returns TRUE if all of the characters were
  705.  * deleted, and FALSE if they were not (because dot ran into the end of the
  706.  * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
  707.  */
  708. PASCAL NEAR ldelete(n, kflag, rawmode, margmode)
  709.  
  710. long n;         /* # of chars to delete */
  711. int kflag;      /* put killed text in kill buffer flag */
  712. int rawmode;    /* treat folds like normal lines */
  713. int margmode;   /* don't allow deletion to left of margin */
  714.  
  715. {
  716.         register char   *cp1;
  717.         register char   *cp2;
  718.         register LINE   *dotp;
  719.         register int    doto;
  720.         register int    chunk;
  721.         register WINDOW *wp;
  722.                  LINE   *olddotp;
  723.                  int    olddoto;
  724.         int i;                  /* MJB: 20-Sep-89 */
  725.         int cmark;              /* current mark */
  726.  
  727.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  728.                 return(rdonly());       /* we are in read only mode     */
  729.  
  730.         /* check if before left margin of an open fold */
  731.         if ((curwp->w_dotp->l_type == LNORMAL) && margmode &&
  732.             (curwp->w_doto < curwp->w_dotp->l_lmargin))
  733.                 return(beep());
  734.  
  735.         /* check if attempting to edit a fold symbol. MJB: 20-Sep-89 */
  736.         if (((curwp->w_dotp->l_type == LEOFOLD) ||
  737.              (curwp->w_dotp->l_type == LEOEFOLD)) && !rawmode)
  738.                 return(beep());
  739.         if (((curwp->w_dotp->l_type == LSOFOLD) ||
  740.              (curwp->w_dotp->l_type == LSOEFOLD)) && !rawmode) {
  741.                 if (curwp->w_dotp->l_type == LSOFOLD)
  742.                         i = indx(curwp->w_dotp->l_text, FOLDSYMBOL);
  743.                 else if (curwp->w_dotp->l_type == LSOEFOLD)
  744.                         i = indx(curwp->w_dotp->l_text, BEGINFOLD);
  745.                 if ((curwp->w_doto >= i) && 
  746.                     (curwp->w_doto < i + strlen(FOLDSYMBOL)))
  747.                         return(beep()); /* in fold symbol */
  748.                 else if (curwp->w_doto + n > curwp->w_dotp->l_used)
  749.                         return(beep()); /* would cause line wrap */
  750.                 else if ((curwp->w_doto < i) && (curwp->w_doto + n > i))
  751.                         n = i - curwp->w_doto; /* would get into fold symbol */
  752.  
  753.                 if ((n > 0) && (curwp->w_doto + n <= i)) 
  754.                         undentfold(n, i, kflag, rawmode, margmode);
  755.         }
  756.  
  757.         while (n != 0L) {
  758.                 dotp = curwp->w_dotp;
  759.                 doto = curwp->w_doto;
  760.                 if (dotp == curbp->b_linep)     /* Hit end of buffer.   */
  761.                         return(FALSE);
  762.                 chunk = dotp->l_used-doto;      /* Size of chunk.       */
  763.                 if ((long)chunk > n)
  764.                         chunk = (int)n;
  765.                 if (chunk == 0) {               /* End of line, merge.  */
  766.                         lchange(WFHARD);
  767.                         /* last newline is special case in rawmode */
  768.                         if (ldelnewline(rawmode && (n > 1)) == FALSE
  769.                         || (kflag!=FALSE && kinsert('\r')==FALSE))
  770.                                 return(FALSE);
  771.                         --n;
  772.                         continue;
  773.                 }
  774.                 lchange(WFEDIT);
  775.                 cp1 = &dotp->l_text[doto];      /* Scrunch text.        */
  776.                 cp2 = cp1 + chunk;
  777.                 if (kflag != FALSE) {           /* Kill?                */
  778.                         while (cp1 != cp2) {
  779.                                 if (kinsert(*cp1) == FALSE)
  780.                                         return(FALSE);
  781.                                 ++cp1;
  782.                         }
  783.                         cp1 = &dotp->l_text[doto];
  784.                 }
  785.                 while (cp2 != &dotp->l_text[dotp->l_used])
  786.                         *cp1++ = *cp2++;
  787.  
  788.                 dotp->l_used -= chunk;
  789.                 wp = wheadp;                    /* Fix windows          */
  790.                 while (wp != NULL) {
  791.                         if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  792.                                 wp->w_doto -= chunk;
  793.                                 if (wp->w_doto < doto)
  794.                                         wp->w_doto = doto;
  795.                                 if (margmode)
  796.                                         marginchk(wp->w_dotp,
  797.                                                   loffset(wp->w_dotp));
  798.  
  799.                         }
  800.                         for (cmark = 0; cmark < NMARKS; cmark++) {
  801.                                 if (wp->w_markp[cmark]==dotp && wp->w_marko[cmark]>=doto) {
  802.                                         wp->w_marko[cmark] -= chunk;
  803.                                         if (wp->w_marko[cmark] < doto)
  804.                                                 wp->w_marko[cmark] = doto;
  805.                                 }
  806.                         }
  807.                         wp = wp->w_wndp;
  808.                 }
  809.                 n -= (long)chunk;
  810.         }
  811.         return(TRUE);
  812. }
  813.  
  814. /* getctext:    grab and return a string with the text of
  815.                 the current line
  816. */
  817.  
  818. char *PASCAL NEAR getctext()
  819.  
  820. {
  821.         register LINE *lp;      /* line to copy */
  822.         register int size;      /* length of line to return */
  823.         register char *sp;      /* string pointer into line */
  824.         register char *dp;      /* string pointer into returned line */
  825.         char rline[NSTRING];    /* line to return */
  826.  
  827.         /* find the contents of the current line and its length */
  828.         lp = curwp->w_dotp;
  829.         sp = lp->l_text;
  830.         size = lp->l_used;
  831.         if (size >= NSTRING)
  832.                 size = NSTRING - 1;
  833.  
  834.         /* copy it across */
  835.         dp = rline;
  836.         while (size--)
  837.                 *dp++ = *sp++;
  838.         *dp = 0;
  839.         return(rline);
  840. }
  841.  
  842. /* putctext:    replace the current line with the passed in text        */
  843.  
  844. PASCAL NEAR putctext(iline)
  845.  
  846. char *iline;    /* contents of new line */
  847.  
  848. {
  849.         register int status;
  850.  
  851.         /* delete the current line */
  852.         curwp->w_doto = 0;      /* starting at the beginning of the line */
  853.         if ((status = killtext(TRUE, 1)) != TRUE)
  854.                 return(status);
  855.  
  856.         /* insert the new line */
  857.         if ((status = linstr(iline)) != TRUE)
  858.                 return(status);
  859.         status = lnewline();
  860.         backline(TRUE, 1, FALSE);
  861.         return(status);
  862. }
  863.  
  864. /*
  865.  * Delete a newline. Join the current line with the next line. If the next line
  866.  * is the magic header line always return TRUE; merging the last line with the
  867.  * header line can be thought of as always being a successful operation, even
  868.  * if nothing is done, and this makes the kill buffer work "right". Easy cases
  869.  * can be done by shuffling data around. Hard cases require that lines be moved
  870.  * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
  871.  * "ldelete" only.
  872.  */
  873. PASCAL NEAR ldelnewline(rawmode)
  874. int     rawmode;        /* ignore line types if true. MJB: 29-Sep-89 */
  875. {
  876.         register char   *cp1;
  877.         register char   *cp2;
  878.         register LINE   *lp1;
  879.         register LINE   *lp2;
  880.         register LINE   *lp3;
  881.         register WINDOW *wp;
  882.         int cmark;              /* current mark */
  883.  
  884.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  885.                 return(rdonly());       /* we are in read only mode     */
  886.  
  887.         if ((curwp->w_dotp->l_type != LNORMAL) && !rawmode) /* don't allow for folds */
  888.                 return(beep());               /* MJB: 20-Sep-89        */
  889.  
  890.         lp1 = curwp->w_dotp;
  891.         lp2 = lp1->l_fp;
  892.  
  893.         /*if ((lp2->l_type != LNORMAL) && (lp1->l_used > 0) && !rawmode)*/
  894.         if ((lp2->l_type != LNORMAL) && (lp1->l_used > lp1->l_lmargin) && !rawmode)
  895.                 return(beep()); /* can't concatenate lines. MJB: 22-Sep-89 */
  896.  
  897.         if ((lp2->l_type != LNORMAL) && (lp1->l_used <= lp1->l_lmargin) && !rawmode)
  898.                 lp1->l_used = 0;
  899.  
  900.         if (lp2 == curbp->b_linep) {            /* At the buffer end.   */
  901.                 if (lp1->l_used == 0)           /* Blank line.          */
  902.                         lfree(lp1);
  903.                 return(TRUE);
  904.         }
  905.         if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  906.                 cp1 = &lp1->l_text[lp1->l_used];
  907.                 cp2 = &lp2->l_text[(rawmode || (lp2->l_type != LNORMAL)) ? 
  908.                                    0 : lp2->l_lmargin];
  909.                 while (cp2 != &lp2->l_text[lp2->l_used])
  910.                         *cp1++ = *cp2++;
  911.                 wp = wheadp;
  912.                 while (wp != NULL) {
  913.                         if (wp->w_linep == lp2)
  914.                                 wp->w_linep = lp1;
  915.                         if (wp->w_dotp == lp2) {
  916.                                 wp->w_dotp  = lp1;
  917.                                 wp->w_doto += lp1->l_used;
  918.                         }
  919.                         for (cmark = 0; cmark < NMARKS; cmark++) {
  920.                                 if (wp->w_markp[cmark] == lp2) {
  921.                                         wp->w_markp[cmark]  = lp1;
  922.                                         wp->w_marko[cmark] += lp1->l_used;
  923.                                 }
  924.                         }
  925.                         wp = wp->w_wndp;
  926.                 }
  927.  
  928.                 /* set line type, and if necessary fold pointers. MJB: 22-Sep-89 */
  929.                 if ((lp2->l_type != LNORMAL) && !rawmode) {
  930.                         lp1->l_type = lp2->l_type;
  931.                         lp1->l_foldp = lp2->l_foldp;
  932.                         lp1->l_foldp->l_foldp = lp1;
  933. /*                      lp1->l_lmargin = lp2->l_lmargin;*/
  934.                         lp1->l_lmargin = minleftmarg(lp1);
  935.                 }
  936.                 else
  937.                         lp1->l_type = LNORMAL;
  938.  
  939.                 lp1->l_used += (lp2->l_used - 
  940.                                 ((rawmode || (lp2->l_type != LNORMAL)) ? 
  941.                                 0 : lp2->l_lmargin));
  942.                 lp1->l_fp = lp2->l_fp;
  943.                 lp2->l_fp->l_bp = lp1;
  944.                 free((char *) lp2);
  945.                 return(TRUE);
  946.         }
  947.         if ((lp3=lalloc(lp1->l_used + lp2->l_used - 
  948.                         ((rawmode || (lp2->l_type != LNORMAL)) ? 
  949.                         0 : lp2->l_lmargin))) == NULL)
  950.                 return(FALSE);
  951.  
  952.         /* set line type, and if necessary fold pointers. MJB: 22-Sep-89 */
  953.         if (rawmode)
  954.                 lp3->l_type = LNORMAL;
  955.         else {
  956.                 lp3->l_type = lp2->l_type;
  957.                 if ((lp3->l_foldp = lp2->l_foldp) != (LINE *) NULL)
  958.                         lp3->l_foldp->l_foldp = lp3;
  959.         }
  960.  
  961.         cp1 = &lp1->l_text[0];
  962.         cp2 = &lp3->l_text[0];
  963.         while (cp1 != &lp1->l_text[lp1->l_used])
  964.                 *cp2++ = *cp1++;
  965.         cp1 = &lp2->l_text[(rawmode || (lp2->l_type != LNORMAL)) ? 
  966.                            0 : lp2->l_lmargin];
  967.         while (cp1 != &lp2->l_text[lp2->l_used])
  968.                 *cp2++ = *cp1++;
  969.         lp1->l_bp->l_fp = lp3;
  970.         lp3->l_fp = lp2->l_fp;
  971.         lp2->l_fp->l_bp = lp3;
  972.         lp3->l_bp = lp1->l_bp;
  973.         if (rawmode)
  974.                 lp3->l_lmargin = 0;
  975.         else {
  976.                 lp3->l_lmargin = minleftmarg(lp3);
  977.                 marginchk(lp3, loffset(lp3));
  978.         }
  979.         wp = wheadp;
  980.         while (wp != NULL) {
  981.                 if (wp->w_linep==lp1 || wp->w_linep==lp2)
  982.                         wp->w_linep = lp3;
  983.                 if (wp->w_dotp == lp1)
  984.                         wp->w_dotp  = lp3;
  985.                 else if (wp->w_dotp == lp2) {
  986.                         wp->w_dotp  = lp3;
  987.                         wp->w_doto += lp1->l_used;
  988.                 }
  989.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  990.                         if (wp->w_markp[cmark] == lp1)
  991.                                 wp->w_markp[cmark]  = lp3;
  992.                         else if (wp->w_markp[cmark] == lp2) {
  993.                                 wp->w_markp[cmark]  = lp3;
  994.                                 wp->w_marko[cmark] += lp1->l_used;
  995.                         }
  996.                 }
  997.                 wp = wp->w_wndp;
  998.         }
  999.         free((char *) lp1);
  1000.         free((char *) lp2);
  1001.         return(TRUE);
  1002. }
  1003.  
  1004. /*
  1005.  * Delete all of the text saved in the kill buffer. Called by commands when a
  1006.  * new kill context is being created. The kill buffer array is released, just
  1007.  * in case the buffer has grown to immense size. No errors.
  1008.  */
  1009. PASCAL NEAR kdelete()
  1010. {
  1011.         KILL *kp;       /* ptr to scan kill buffer chunk list */
  1012.  
  1013.         if (kbufh != NULL) {
  1014.  
  1015.                 /* first, delete all the chunks */
  1016.                 kbufp = kbufh;
  1017.                 while (kbufp != NULL) {
  1018.                         kp = kbufp->d_next;
  1019.                         free(kbufp);
  1020.                         kbufp = kp;
  1021.                 }
  1022.  
  1023.                 /* and reset all the kill buffer pointers */
  1024.                 kbufh = kbufp = NULL;
  1025.                 kused = KBLOCK;                 
  1026.         }
  1027.  
  1028.         killfoldbound = FALSE;
  1029. }
  1030.  
  1031. /*
  1032.  * Insert a character to the kill buffer, allocating new chunks as needed.
  1033.  * Return TRUE if all is well, and FALSE on errors.
  1034.  */
  1035.  
  1036. PASCAL NEAR kinsert(c)
  1037.  
  1038. char c;         /* character to insert in the kill buffer */
  1039.  
  1040. {
  1041.         KILL *nchunk;   /* ptr to newly malloced chunk */
  1042.  
  1043.         /* check to see if we need a new chunk */
  1044.         if (kused >= KBLOCK) {
  1045.                 if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULL)
  1046.                         return(FALSE);
  1047.                 if (kbufh == NULL)      /* set head ptr if first time */
  1048.                         kbufh = nchunk;
  1049.                 if (kbufp != NULL)      /* point the current to this new one */
  1050.                         kbufp->d_next = nchunk;
  1051.                 kbufp = nchunk;
  1052.                 kbufp->d_next = NULL;
  1053.                 kused = 0;
  1054.         }
  1055.  
  1056.         /* and now insert the character */
  1057.         kbufp->d_chunk[kused++] = c;
  1058.         return(TRUE);
  1059. }
  1060.  
  1061. /*
  1062.  * Yank text back from the kill buffer. This is really easy. All of the work
  1063.  * is done by the standard insert routines. All you do is run the loop, and
  1064.  * check for errors. Bound to "C-Y".
  1065.  * After the yank, parse the region to check for folds, and set line types
  1066.  * and pointers as required. Also add indentation if yanking into open fold.
  1067.  */
  1068. PASCAL NEAR yank(f, n)
  1069. {
  1070.         register int    c;
  1071.         register int    i;
  1072.         register char   *sp;    /* pointer into string to insert */
  1073.         KILL *kp;               /* pointer into kill buffer */
  1074.         LINE *startp;           /* start of yanked area */
  1075.         LINE *lp1;              /* pointers within region */
  1076.         int  margin, marg;      /* margins within yanked region */
  1077.  
  1078.         if (curbp->b_mode&MDVIEW)       /* don't allow this command if  */
  1079.                 return(rdonly());       /* we are in read only mode     */
  1080.  
  1081.         if ((curwp->w_dotp->l_type != LNORMAL) && killedcr) /* don't yank onto fold lines */
  1082.                 return(beep());                             /* MJB: 20-Sep-89             */
  1083.  
  1084.         if (n < 0)
  1085.                 return(FALSE);
  1086.         /* make sure there is something to yank */
  1087.         if (kbufh == NULL)
  1088.                 return(TRUE);           /* not an error, just nothing */
  1089.  
  1090.         if ((curwp->w_doto < curwp->w_dotp->l_lmargin) || killfoldbound)
  1091.                 curwp->w_doto = curwp->w_dotp->l_lmargin;
  1092.  
  1093.         startp = curwp->w_dotp->l_bp;   /* remember where we started */
  1094.  
  1095.         /* for each time.... */
  1096.         while (n--) {
  1097.                 kp = kbufh;
  1098.                 while (kp != NULL) {
  1099.                         if (kp->d_next == NULL)
  1100.                                 i = kused;
  1101.                         else
  1102.                                 i = KBLOCK;
  1103.                         sp = kp->d_chunk;
  1104.                         while (i--) {
  1105.                                 if ((c = *sp++) == '\r') {
  1106.                                         if (lnewline() == FALSE)
  1107.                                                 return(FALSE);
  1108.                                 } else {
  1109.                                         if (linsert(1, c, FALSE) == FALSE)
  1110.                                                 return(FALSE);
  1111.                                 }
  1112.                         }
  1113.                         kp = kp->d_next;
  1114.                 }
  1115.         }
  1116.  
  1117.         /* parse region to see if we yanked any folds. MJB: 26-Sep-89 */
  1118.  
  1119.         lp1 = startp->l_fp;
  1120.         if (startp->l_type == LSOEFOLD)
  1121.                 margin = loffset(startp);
  1122.         else
  1123.                 margin = startp->l_lmargin;
  1124.  
  1125.         while (lp1 != curwp->w_dotp) {
  1126.  
  1127.                 lp1->l_lmargin = margin;
  1128.                 if ((marg = tindx(lp1->l_text, FOLDSYMBOL, lp1->l_used)) != -1) {
  1129.                         lp1->l_type = LSOFOLD;
  1130.                         pushline(lp1); 
  1131.                         margin = marg;
  1132.                 }
  1133.                 else if ((marg = tindx(lp1->l_text, BEGINFOLD, lp1->l_used)) != -1) {
  1134.                         lp1->l_type = LSOEFOLD;
  1135.                         pushline(lp1); 
  1136.                         margin = marg;
  1137.                 }
  1138.                 else if ((marg = tindx(lp1->l_text, ENDFOLD, lp1->l_used)) != -1) {
  1139.                         if (linelist->fll_bp->fll_line != (LINE *)NULL) {
  1140.                                 lp1->l_foldp = popline();
  1141.                                 lp1->l_foldp->l_foldp = lp1;
  1142.                                 margin = lp1->l_foldp->l_lmargin;
  1143.                                 lp1->l_lmargin = margin; /* was too right */
  1144.                                 if (lp1->l_foldp->l_type == LSOFOLD)
  1145.                                         lp1->l_type = LEOFOLD;
  1146.                                 else
  1147.                                         lp1->l_type = LEOEFOLD;
  1148.                         }
  1149.                         else { /* Just to be safe! */
  1150.                                 lp1->l_type = LNORMAL;
  1151.                                 lp1->l_foldp = (LINE *)NULL;
  1152.                                 mlwrite(TEXT231);
  1153. /*                                      "Missing start-fold Marker - */
  1154.                         }
  1155.                 }
  1156.                 lp1 = lp1->l_fp;
  1157.         }
  1158.  
  1159.         /* check to see if matching number of start/end fold markers */
  1160.         /* if not try to tidy up a bit. MJB: 13-Nov-89 */
  1161.         while (linelist->fll_bp->fll_line != (LINE *)NULL) {
  1162.                 lp1 = popline();
  1163.                 lp1->l_type = LNORMAL;
  1164.                 mlwrite(TEXT230);
  1165. /*                          "Missing end-fold Marker" */
  1166.         }
  1167.  
  1168.         return(TRUE);
  1169. }
  1170.  
  1171.  
  1172. /* Initialise the linelist to hold start-fold lines.
  1173.  * MJB: 15-Sep-89.
  1174.  */
  1175. PASCAL NEAR initlinelist()
  1176. {
  1177.         if ((linelist = (FOLDLINELIST *)malloc(sizeof(FOLDLINELIST))) == NULL) {
  1178.                 mlwrite(TEXT99);
  1179.                 /* "[OUT OF MEMORY]" */
  1180.                 return(NULL);
  1181.         }
  1182.         linelist->fll_fp = linelist;
  1183.         linelist->fll_bp = linelist;
  1184.         linelist->fll_line = (LINE *)NULL;
  1185.         return(TRUE);
  1186. }
  1187.  
  1188.  
  1189. /* Add a line to the list of start-fold lines.
  1190.  * MJB: 15-Sep-89.
  1191.  */
  1192. PASCAL NEAR pushline(lp)
  1193. LINE *lp;
  1194. {
  1195.         struct FOLDLINELIST *lele;
  1196.         struct FOLDLINELIST *lele2;
  1197.  
  1198.         if ((lele = (FOLDLINELIST *)malloc(sizeof(FOLDLINELIST))) == NULL) {
  1199.                 mlwrite(TEXT99);
  1200.                 /* "[OUT OF MEMORY]" */
  1201.                 return(NULL);
  1202.         }
  1203.         lele->fll_line = lp;
  1204.         lele2 = linelist->fll_bp;
  1205.         lele2->fll_fp = lele;
  1206.         lele->fll_fp = linelist;
  1207.         lele->fll_bp = lele2;
  1208.         linelist->fll_bp = lele;
  1209.         lele->fll_line = lp;
  1210.         return(TRUE);
  1211. }
  1212.  
  1213.  
  1214. LINE *PASCAL NEAR popline()
  1215. {
  1216.         struct FOLDLINELIST     *lele;
  1217.         struct LINE             *lp;
  1218.  
  1219.         lele = linelist->fll_bp;
  1220.         lele->fll_bp->fll_fp = lele->fll_fp;
  1221.         lele->fll_fp->fll_bp = lele->fll_bp;
  1222.         lp = lele->fll_line;
  1223.         free((FOLDLINELIST *) lele);
  1224.         return(lp);
  1225. }
  1226.  
  1227.